// ╔═══════════════════════════════════════════════════════════════════════════╗
//                                控件工厂
// ╚═══════════════════════════════════════════════════════════════════════════╝
export class ControlFactory {

    static create(plugin) {
        return {
            ...new TextControl(plugin, 'Text').controls,
            ...new TextareaControl(plugin, 'Textarea').controls,
            ...new DropdownControl(plugin, 'Dropdown').controls,
            ...new CheckboxControl(plugin, 'Checkbox').controls,
            ...new ColorPickerControl(plugin, 'ColorPicker').controls,
            ...new IntSliderControl(plugin, 'IntSlider').controls,
        };
    }
}

// ╔═══════════════════════════════════════════════════════════════════════════╗
//                                控件基类
// ╚═══════════════════════════════════════════════════════════════════════════╝
class DefaultControl {

    constructor(plugin, type) {
        if (new.target === DefaultControl) {
            throw new Error('Cannot instantiate abstract class');
        }

        this.widgetConfig = plugin.config.WIDGET_CONFIG;
        this.constants = plugin.constants;
        this.$container = plugin.$container;
        this.config = Object.entries(this.constants.CONTROLS_CONFIG).filter(([_key, spec]) => spec.widget === type);

        this.controls = {};

        this.init();
    }

    /**
     * 初始化控件
     */
    init() {
        this._validateConfig();
        this.create();
    }

    /**
     * 初始化前的钩子函数
     * @returns {Array} 处理后的配置数组
     */
    beforeCreate() {
        return this.config;
    }

    /**
     * 初始化后的钩子函数
     * @param {Array} config 处理后的配置数组
     */
    afterCreate(config) {
    }

    /**
     * 验证配置
     */
    _validateConfig() {
        if (!this.constants.CLASS_PREFIX) {
            throw new Error('Missing required config: CLASS_PREFIX');
        }
    }

    /**
     * 创建单个控件
     * @param {string} key 控件键名
     * @param {Object} spec 控件配置
     * @returns {Object} 控件对象
     */
    _createSingleControl(key, spec) {
        const widgetType = spec.widget;
        const defaultValue = spec.default;

        const valueKey = this.widgetConfig[widgetType].valueKey || 'value';
        const selector = this.widgetConfig[widgetType].selector || '';
        const elementSelector = `.${this.constants.CLASS_PREFIX}-${key} ${selector}`;
        const $element = this.$container.find(elementSelector);

        return {
            widget: widgetType,
            shouldListen: spec.shouldListen || true,
            selector: elementSelector,
            spec: spec,
            element: $element,
            getValue: () => {
                const element = $element[0];
                return element ? element[valueKey] : defaultValue;
            },
            reset: () => {
                const element = $element[0];
                if (element) element[valueKey] = defaultValue;
            },
        }
    }

    /**
     * 创建所有控件
     */
    create() {
        const processedConfig = this.beforeCreate();
        this._validateConfig(processedConfig);

        processedConfig.forEach(([key, spec]) => {
            this.controls[key] = this._createSingleControl(key, spec);
        })
        this.afterCreate(processedConfig);
    }
}

// ╔═══════════════════════════════════════════════════════════════════════════╗
//                           TextControl 控件
// ╚═══════════════════════════════════════════════════════════════════════════╝
class TextControl extends DefaultControl{}

// ╔═══════════════════════════════════════════════════════════════════════════╗
//                           DefaultControl 控件
// ╚═══════════════════════════════════════════════════════════════════════════╝
class TextareaControl extends DefaultControl{}

// ╔═══════════════════════════════════════════════════════════════════════════╗
//                            DropdownControl 控件
// ╚═══════════════════════════════════════════════════════════════════════════╝
class DropdownControl extends DefaultControl{}

// ╔═══════════════════════════════════════════════════════════════════════════╗
//                            CheckboxControl 控件
// ╚═══════════════════════════════════════════════════════════════════════════╝
class CheckboxControl extends DefaultControl{}

// ╔═══════════════════════════════════════════════════════════════════════════╗
//                            ColorPickerControl 控件
// ╚═══════════════════════════════════════════════════════════════════════════╝
class ColorPickerControl extends DefaultControl {

    /**
     * 新增颜色取样器控件 - Text
     * @param {Array} config 处理后的配置数组
     */
    afterCreate(config) {
        config.forEach(([key, spec]) => {
            const widgetType = spec.widget;
            const defaultValue = spec.default;
            const selector = 'input[type="text"]';
            const elementSelector = `.${this.constants.CLASS_PREFIX}-${key} ${selector}`;
            const $element = this.$container.find(elementSelector);

            this.controls[`${key}Text`] = {
                widget: widgetType,
                shouldListen: true,
                event: ["change"],
                selector: elementSelector,
                element: $element,
                getValue: () => {
                    const element = $element[0];
                    return element? element.value : defaultValue;
                },
                reset: () => {
                    const element = $element[0];
                    if (element) element.value = defaultValue;
                }
            }
        })
    }
}

// ╔═══════════════════════════════════════════════════════════════════════════╗
//                            IntSliderControl 控件
// ╚═══════════════════════════════════════════════════════════════════════════╝
export class IntSliderControl extends DefaultControl {

    /**
     * 新增滑块控件 - Target、Origin、Handle
     * @param {Array} config 处理后的配置数组
     */
    afterCreate(config) {
        config.forEach(([key, spec]) => {
            const widgetType = spec.widget;
            const defaultValue = spec.default;

            const targetKey = `${key}Target`;
            const originKey = `${key}Origin`;
            const handleKey = `${key}Handle`;

            const targetSelector = '.noUi-target';
            const originSelector = '.noUi-origin';
            const handleSelector = '.noUi-handle';

            const targetElementSelector = `.${this.constants.CLASS_PREFIX}-${key} ${targetSelector}`;
            const originElementSelector = `.${this.constants.CLASS_PREFIX}-${key} ${originSelector}`;
            const handleElementSelector = `.${this.constants.CLASS_PREFIX}-${key} ${handleSelector}`;

            const $targetElement = this.$container.find(targetElementSelector);
            const $originElement = this.$container.find(originElementSelector);
            const $handleElement = this.$container.find(handleElementSelector);

            this.controls[targetKey] = {
                widget: widgetType,
                shouldListen: false,
                selector: targetElementSelector,
                element: $targetElement,
            };
            this.controls[originKey] = {
                widget: widgetType,
                shouldListen: false,
                selector: originElementSelector,
                element: $originElement,
                reset: () => {
                    if ($originElement.length > 0) {
                        $originElement.css("transform", this.calcSliderTranslate(key, defaultValue))
                    }
                },
            };
            this.controls[handleKey] = {
                widget: widgetType,
                shouldListen: false,
                selector: handleElementSelector,
                element: $handleElement,
                reset: () => {
                    if ($handleElement.length > 0) {
                        const toFixed = spec.toFixed || 1;
                        $handleElement.attr("aria-valuenow", Number(defaultValue).toFixed(toFixed));
                    }
                },
            }
        })
    }

    /**
     * 获取有效滑块值（带缩放因子）
     * @param {string} value 原始值
     * @param {string} key 配置项键名
     * @param {number} min 最小值，默认为0
     * @returns {string} 有效值
     */
    getSliderValue(value, key, min = 0) {
        if (value === '0') return '0';
        const configObj = Object.fromEntries(this.config);
        const spec = configObj[key];
        const scaleFactor =spec.scaleFactor || 1;
        const toFixed =spec.toFixed || 1;
        const symbol = spec.symbol || "";
        return `${((Math.max(min, Number(value)) || spec.default) * scaleFactor).toFixed(toFixed)}${symbol}`;
    }

    /**
     * 计算滑块的 translate 值
     * @param {string} key 配置项键名
     * @param {number} defaultValue 默认值
     * @returns {string} translate 值
     */
    calcSliderTranslate(key, defaultValue) {
        const handle = `${key}Handle`;
        if (!Object.keys(this.controls).includes(handle)) {
            console.warn(`未找到'${key}'滑块定义的 .noUi-handle 选择器，请检查配置项！`);
        }
        const posyMax = this.controls[`${key}Handle`].element.attr("aria-valuemax")
        return `translate(-${(posyMax - defaultValue) * (1000 / posyMax)}%, 0px)`
    }
}